<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>

<body>
  <span id="one">123</span>
  <div id="two">123</div>
  <script>
    // 函数柯里化应用

    // 1. 参数复用 
    function curryArgs(protocol) {
      return function (hostname) {
        return function (pathname) {
          console.log(`${protocol}${hostname}${pathname}`);
        }
      }
    }

    const url_https = curryArgs('https://')('www.bilibili.com')

    url_https('/点赞')
    url_https('/投币')
    url_https('/收藏')


    // 2. 提前确认——浏览器事件监听判断

    // 在定义addEvent时用立即执行函数判断浏览器为哪种事件监听
    var addEvent = (function () {
      if (window.addEventListener) { //判断是否支持
        // el-绑定元素 sType-事件名 fn-事件处理函数 capture-是否支持捕获
        // 返回对应的事件监听函数
        return function (el, sType, fn, capture) {
          el.addEventListener(sType, function (e) {
            fn.call(el, e);
          }, (capture));
        };
      } else if (window.attachEvent) {
        return function (el, sType, fn, capture) {
          el.attachEvent("on" + sType, function (e) {
            fn.call(el, e);
          });
        };
      }
    })();


    var span = document.getElementById("one");
    var div = document.getElementById("two");
    // 后续多次使用时无需判断浏览器
    addEvent(span, 'click', function () { console.log("span") }, false)
    addEvent(div, 'click', function () { console.log("div") }, false)


    // 3. 延迟执行
    // 任意个参数、任意次调用都可输出
    // add(1)(2)(3)=6  add(1,2,3)(4)=10

    // 每次调用传参时都只是保存了传入的参数。
    // 只有在真正输出的时候才调用了函数的 toString 方法执行代码
    function add() {
      // 将首次调用add传入的参数储存在数组中
      let args = Array.prototype.slice.call(arguments)

      // 定义一个内部函数 
      let inner = function () {
        // 拼接调用此内部函数时传入的参数
        args.push(...arguments)
        // 继续返回内部函数
        return inner
      }
      // 修改内部函数的toString方法为显示参数累加的值
      inner.toString = function () {
        return args.reduce((pre, cur) => {
          return pre + cur
        })
      }

      // 返回内部函数
      return inner
    }
    let a = add(1)(2)(3)
    let b = add(1, 2, 3)()(5)
    console.log(a);
    console.log(b);


    // 参数复用应用
    const arr1 = [
      { name: 'zs', age: 28 },
      { name: 'ls', age: 28 },
      { name: 'ww', age: 28 },
      { name: 'zl', age: 28 }
    ]
    const arr2 = [
      { englishName: 'qwe', age: 28 },
      { englishName: 'weq', age: 28 },
      { englishName: 'adds', age: 28 },
      { englishName: 'dsad', age: 28 }
    ]

    // 业务需求：分别拿到数组中的名字
    // 原始做法
    // 每个数组都需要分别输入自己的属性名
    const arr3 = arr1.map(item => item.name)
    const arr4 = arr2.map(item => item.englishName)
    console.log(arr3);
    console.log(arr4);

    // 柯里化，两个参数：name element
    const currying = name => element => element[name]

    const curry1 = currying('name') // element => element['name']
    const curry2 = currying('englishName') // element => element['englishName']
    // 数组中的每个对象
    console.log(arr1.map(curry1));
    console.log(arr2.map(curry2));
  </script>
</body>

</html>